package com.gl.order.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gl.order.commom.constant.OrderFileType;
import com.gl.order.commom.util.ImageUtils;
import com.gl.order.entity.*;
import com.gl.order.entity.docs.OrderWord;
import com.gl.order.entity.dto.*;
import com.gl.order.entity.excel.OrderExcel;
import com.gl.order.entity.vo.*;
import com.gl.order.mapper.TOrderFileMapper;
import com.gl.order.mapper.TOrderMapper;
import com.gl.order.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: liangSY
 * @Date: 2021/6/26
 * @ClassName: OrderServiceImpl
 * @Description: OrderServiceImpl描述
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class OrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements OrderService {

    LiningService liningService;

    OrderNumberInfoService orderNumberInfoService;

    TOrderFileMapper tOrderFileMapper;

    FileService fileService;

    OrderSizeService orderSizeService;


    public OrderServiceImpl(LiningService liningService, OrderNumberInfoService orderNumberInfoService, TOrderFileMapper tOrderFileMapper, FileService fileService, OrderSizeService orderSizeService) {
        this.liningService = liningService;
        this.orderNumberInfoService = orderNumberInfoService;
        this.tOrderFileMapper = tOrderFileMapper;
        this.fileService = fileService;
        this.orderSizeService = orderSizeService;
    }

    @Override
    public TOrder add(OrderDto dto) {
        TOrder check = findByNo(dto.getOrderNo());
        Assert.isNull(check, "订单编号已存在");
        TOrder order = new TOrder();
        BeanUtils.copyProperties(dto, order);
        // 获取订单付款状态
        String payState = payState(dto.getDeduction(), dto.getAdvance(), dto.getNum(), dto.getPrice());
        order.setPayState(payState);
        save(order);
        // 添加尺寸
        orderNumberInfoService.addOrderNum(order.getId(), order.getOrderNo(), dto.getSizes());
        // 添加面料数据
        liningService.addLinings(order.getId(), order.getOrderNo(), dto.getLinings());
        return order;
    }

    @Override
    public TOrder copy(OrderCopyDto dto) {
        TOrder check = findByNo(dto.getOrderNo());
        Assert.isNull(check, "订单编号已存在");
        TOrder order = getById(dto.getId());
        order.setId(null);
        order.setState(null);
        order.setIsCopy(dto.getIsCopy());
        order.setOrderNo(dto.getOrderNo());
        order.setCreateTime(LocalDateTime.now());
        // 复制订单
        save(order);
        // 复制订单尺码
        List<OrderNumberInfo> orderNumberInfos = orderNumberInfoService.getByOrderId(dto.getId());
        orderNumberInfos.stream().forEach(orderNumberInfo -> {
            orderNumberInfo.setOrderId(order.getId());
            orderNumberInfo.setId(null);
            orderNumberInfoService.save(orderNumberInfo);
        });
        // 复制订单面料
        List<TOrderLining> linings = liningService.getByOrderId(dto.getId());
        linings.stream().forEach(lining -> {
            lining.setOrderId(order.getId());
            lining.setId(null);
            liningService.save(lining);
        });
        // 复制订单图片
        List<TFile> files = tOrderFileMapper.getFilesByOrderId(dto.getId());
        List<TFile> copyFiles = new ArrayList<>();
        files.forEach(file -> {
            TFile cfile = fileService.copy(file);
            if (!Objects.isNull(cfile)) {
                copyFiles.add(cfile);
            }

        });
        // 图片-订单关系
        copyFiles.stream().forEach(t -> {
            TOrderFile orderFile = TOrderFile.builder()
                    .fileId(t.getId())
                    .fileType(t.getFolder())
                    .orderNo(order.getOrderNo())
                    .orderId(order.getId())
                    .build();
            tOrderFileMapper.insert(orderFile);
        });
        return order;
    }

    @Override
    public void editOrder(UpdateOrderDto dto) {
        TOrder check = getById(dto.getId());
        Assert.notNull(check, "找不到指定的订单");
        TOrder order = new TOrder();
        BeanUtils.copyProperties(dto, order);
        // 裁床日期
        order.setCuttingRoomTime(LocalDateTimeUtil.of(DateUtil.parse(dto.getCuttingRoomTime())));
        // 车衣日期
        order.setCarClothesTime(LocalDateTimeUtil.of(DateUtil.parse(dto.getCarClothesTime())));
        // 出货日期
        order.setShipmentTime(LocalDateTimeUtil.of(DateUtil.parse(dto.getShipmentTime())));
        // 印花日期
        order.setPrintingTime(LocalDateTimeUtil.of(DateUtil.parse(dto.getPrintingTime())));
        updateById(order);
        // 添加面料数据（修改之前的面料数据）
        liningService.delByOrder(order.getId());
        liningService.addLinings(order.getId(), order.getOrderNo(), dto.getLinings());
        //添加尺码(删除之前所有的尺码数据，筛选修改太麻烦了，直接清了新增）
        orderNumberInfoService.delByOrder(order.getId());
        orderNumberInfoService.addOrderNum(order.getId(), order.getOrderNo(), dto.getSizes());
        if (!CollectionUtils.isEmpty(dto.getDelIds())) {
            fileService.delFileByIds(dto.getDelIds());
            LambdaQueryWrapper<TOrderFile> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.in(TOrderFile::getFileId, dto.getDelIds());
            tOrderFileMapper.delete(queryWrapper);
        }
    }

    public void saveImg(List<MultipartFile> sampleImgs, List<MultipartFile> payImgs, String oderId, String orderNo) {
        // 添加样板图片
        fileService.addByOrderFileType(oderId, orderNo, sampleImgs, OrderFileType.sample);
        // 添加付款图
        fileService.addByOrderFileType(oderId, orderNo, payImgs, OrderFileType.pay);
    }

    @Override
    public IPage<OrderPageVo> pageList(OrderPageDto dto) {
        Page<OrderPageVo> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        baseMapper.pageOfOrder(page, dto);
        return page;
    }

    @Override
    public IPage<DeliverPageVo> pageList(DeliverPageDto dto) {
        Page<DeliverPageVo> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        baseMapper.deliverPageOfOrder(page, dto);
        return page;
    }

    @Override
    public IPage<PeripheralProductsVo> pageList(PeripheralProductsPageDto dto) {
        Page<PeripheralProductsVo> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        baseMapper.peripheralProductsPageOfOrder(page, dto);
        return page;
    }

    @Override
    public OrderInfoVo getOrderInfo(String orderId) {
        TOrder order = getById(orderId);
        Assert.notNull(order, "找不到指定的订单");
        OrderInfoVo vo = new OrderInfoVo();
        BeanUtils.copyProperties(order, vo);
        // 获取面料信息
        List<TOrderLining> linings = liningService.findByOrderId(orderId);
        vo.setLinings(linings);
        // 尺码数据
        LambdaQueryWrapper<OrderSize> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OrderSize::getSizeType, vo.getProductType());
        List<OrderSize> sizes = orderSizeService.list(queryWrapper);
        List<SizeInfoVo> sizeVos = orderNumberInfoService.getSizeVos(sizes, orderId);
        vo.setSizes(sizeVos);

        Map<String, List<FileVo>> map = getOrderFileVo(orderId);
        // 获取样品图片
        List sampleImgs = map.get(OrderFileType.sample.toString());
        sampleImgs = (null == sampleImgs) ? new ArrayList() : sampleImgs;
        vo.setSampleImgs(sampleImgs);
        // 获取付款图片
        List payImgs = map.get(OrderFileType.pay.toString());
        payImgs = (null == payImgs) ? new ArrayList() : payImgs;
        vo.setPayImgs(payImgs);
        return vo;
    }

    @Override
    public void delOrder(String id) {
        // 删除面料数据
        liningService.delByOrder(id);
        // 删除尺寸数据
        orderNumberInfoService.delByOrder(id);
        // 订单图片
        delFileByOrder(id);
        // 删除订单
        removeById(id);
    }

    @Override
    public void delOrders(List<String> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            ids.stream().forEach(id -> delOrder(id));
        }
    }

    @Override
    public void excelExport(HttpServletResponse response, OrderExcelDto dto) throws IOException {
        List<OrderExcel> excelInfo = baseMapper.getExcelInfo(dto);
        ExcelWriter writer = ExcelUtil.getWriter();
        //自定义标题别名
        writer.addHeaderAlias("time", "日期");
        writer.addHeaderAlias("groupName", "组别");
        writer.addHeaderAlias("marketName", "销售");
        writer.addHeaderAlias("serviceName", "客服");
        writer.addHeaderAlias("orderNo", "订单编号");
        writer.addHeaderAlias("num", "数量");
        writer.addHeaderAlias("price", "单价");
        writer.addHeaderAlias("total", "总金额");
        writer.addHeaderAlias("name", "产品名称");
        writer.addHeaderAlias("cloth", "布料");
        writer.addHeaderAlias("patternName", "纸样");
        writer.addHeaderAlias("color", "色号");
        writer.addHeaderAlias("process", "工艺");
        writer.addHeaderAlias("company", "机构");
        writer.addHeaderAlias("isOld", "新老客户");
        writer.addHeaderAlias("consignee", "收货人");
        writer.addHeaderAlias("phone", "联系电话");
        writer.addHeaderAlias("address", "地址");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        String name = "订单数据-" + System.currentTimeMillis();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name + ".xlsx", "UTF-8") + "");
        OutputStream os = response.getOutputStream();
        writer.write(excelInfo, true);
        writer.flush(os);
        writer.close();
    }

    @Override
    public Map<String, Object> getWordData(String id) {
        Map<String, Object> data = new HashMap<>();
        OrderWord order = this.baseMapper.getOrderWordData(id);
        data = JSONUtil.toBean(JSONUtil.toJsonStr(order), Map.class);
        // 尺码表头
        LambdaQueryWrapper<OrderSize> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OrderSize::getSizeType, order.getProductType());
        List<OrderSize> sizes = orderSizeService.list(queryWrapper);
        data.put("sizeTableHead", sizes);
        // 尺码数据
        List<SizeInfoVo> sizeVos = orderNumberInfoService.getSizeVos(sizes, id);
        data.put("sizeDatas", sizeVos);
        // 效果图
        Map<String, List<FileVo>> map = getOrderAbsoluteFileVo(id);
        List<FileVo> list = map.get(OrderFileType.sample.toString());
        if(!CollectionUtils.isEmpty(list)){
            List<String> samples = new ArrayList<>();
            list.stream().forEach(fileVo -> samples.add(ImageUtils.getImageBase(fileVo.getUrl())));
            data.put("samples", samples);
        }
        return data;
    }

    /**
     * 根据订单编号查询订单
     *
     * @return
     */
    public TOrder findByNo(String no) {
        LambdaQueryWrapper<TOrder> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TOrder::getOrderNo, no);
        TOrder one = getOne(queryWrapper);
        return one;
    }

    /**
     * 订单付款状态
     *
     * @param deduction 抵扣金额
     * @param advance   预付款金额
     * @param num       数量
     * @param price     单价
     * @return
     */
    private String payState(BigDecimal deduction, BigDecimal advance, BigDecimal num, BigDecimal price) {
        BigDecimal zero = BigDecimal.valueOf(0);
        BigDecimal total = NumberUtil.mul(num, price);
        BigDecimal greater = NumberUtil.add(deduction, advance);
        if (NumberUtil.isGreater(total, advance)) {// 预付款等于总价
            // 已付全款
            return "2";
        }
        if (NumberUtil.equals(zero, greater)) {
            // 未付款
            return "0";
        }
        return "1";
    }

    /**
     * 获取订单图片
     *
     * @param id
     * @return
     */
    public Map getOrderFileVo(String id) {
        List<TFile> files = tOrderFileMapper.getFilesByOrderId(id);
        Map<String, List<FileVo>> result = files.stream().collect(Collectors.groupingBy(TFile::getFolder,
                Collectors.mapping((file) -> {
                    FileVo fileVo = fileService.coverFileVo(file);
                    return fileVo;
                }, Collectors.toList())
        ));
        return result;
    }

    public Map getOrderAbsoluteFileVo(String id) {
        List<TFile> files = tOrderFileMapper.getFilesByOrderId(id);
        Map<String, List<FileVo>> result = files.stream().collect(Collectors.groupingBy(TFile::getFolder,
                Collectors.mapping((file) -> {
                    FileVo fileVo = fileService.coverBbsoluteFileVo(file);
                    return fileVo;
                }, Collectors.toList())
        ));
        return result;
    }

    /**
     * 根据id删除订单图片
     *
     * @param id
     */
    public void delFileByOrder(String id) {
        List<String> delFileIds = new ArrayList<>();
        List<TFile> files = tOrderFileMapper.getFilesByOrderId(id);
        files.stream().forEach(file -> {
            fileService.delFile(file);
            delFileIds.add(file.getId());
        });
        fileService.removeByIds(delFileIds);
        // 刪除关联关系
        LambdaQueryWrapper<TOrderFile> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TOrderFile::getOrderId, id);
        tOrderFileMapper.delete(queryWrapper);
    }
}
